/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.commons.tools;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sk.jp.commons.utils.LogMsg;

/**
 * Utility class for loading and accessing multiple property files.
 * <p>
 * All properties files, specified in call <code>init</code> method are loaded
 * during initialization process. Initialization can be performed more than
 * once.
 * <p>
 * Thread safe.
 * 
 * @author Jan Pastor 
 */
public class Properties {

    private static final Logger log = LoggerFactory.getLogger(Properties.class);

    private static Properties instance = null;

    // ----------------------------------------------------------------------

    private HashMap<String, String> properties;

    private Locale locale;

    // ----------------------------------------------------------------------

    /**
     * Initialize singleton instance.
     * 
     * @param propsSrcPaths base name of properties files (package + name),
     *            without '.properties' extension.
     * @param locale locale used for loads language-specific properties files.
     *            Use null to use JVM default locale.
     */
    private Properties(List<String> propsSrcPaths, Locale locale) {
        this.locale = locale != null ? locale : Locale.getDefault();
        if (propsSrcPaths == null) {
            properties = new HashMap<String, String>(0);
        } else {
            properties = new HashMap<String, String>();
            for (String propsSrcPath : propsSrcPaths) {
                ResourceBundle rb = loadProperties(propsSrcPath, locale);
                Enumeration<String> keys = rb.getKeys();
                while (keys.hasMoreElements()) {
                    String key = keys.nextElement();
                    properties.put(key, rb.getString(key));
                }
            }
        }
    }

    // ----------------------------------------------------------------------

    /**
     * Initialize this singleton class.
     * <p>
     * Can be reinitialized using this methos more than once.
     * 
     * @param propsSrcPaths base name of properties files (package + name),
     *            without '.properties' extension.
     * @param locale locale used for loads language-specific properties files.
     *            Use null to use JVM default locale.
     */
    public static synchronized void init(List<String> propsSrcPaths, Locale locale) {
        instance = new Properties(propsSrcPaths, locale);
    }

    /**
     * Returns property value.
     * 
     * @param key property key.
     * @return property value or null if unknown property key.
     */
    public static synchronized String getProperty(String key) {
        if (instance == null) {
            throw new IllegalStateException("Class not initialized");
        }
        return instance.properties.get(key);
    }

    /**
     * Set property value.
     * @param key property key.
     * @param value new value.
     */
    public static synchronized void setProperty(String key, String value) {
        if (instance == null) {
            throw new IllegalStateException("Class not initialized");
        }
        instance.properties.put(key, value);
    }

    /**
     * Returns current locale of properties.
     * 
     * @return current locale of properties.
     */
    public static synchronized Locale getLocale() {
        if (instance == null) {
            throw new IllegalStateException("Class not initialized");
        }
        return instance.locale;
    }

    /**
     * Save properties provided by singleton {@link Properties} to file.
     * @param file target file.
     * @throws IOException if write failed.
     */
    public static synchronized void saveProperties(File file) throws IOException {
        saveProperties(instance.properties, file);
    }

    /**
     * Save given properties to file.
     * @param properties a map of properties to save.
     * @param file target file.
     * @throws IOException if write failed.
     */
    public static synchronized void saveProperties(Map<String,String> properties,
                                                   File file)
                                            throws IOException {
        if(log.isDebugEnabled()){
            log.debug(LogMsg.inp("properties", properties, "file", file));
        }
        
        java.util.Properties props = new java.util.Properties();
        for (Map.Entry<String, String> stringStringEntry : properties.entrySet()) {
            props.setProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
        }
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            props.store(fos, null);
        } finally {
            try {
                if(fos != null){
                    fos.close();
                }
            } catch (IOException ignored) {
            }
        }
    }

    // ----------------------------------------------------------------------

    /**
     * Loads properties as resource bundle from properties file, specified by
     * file base name.
     * 
     * @param propsSrcPath base name of properties file (package + name),
     *            without '.properties' extension.
     * @param locale locale used for loads language-specific properties files.
     * @return properties.
     */
    private static ResourceBundle loadProperties(String propsSrcPath, Locale locale) {
        return PropertyResourceBundle.getBundle(propsSrcPath, locale);
    }

}
